package com.ruoyi.water.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.water.domain.Element;
import com.ruoyi.water.domain.HourData;
import com.ruoyi.water.domain.MeterAnalyse;
import com.ruoyi.water.mapper.MeterAnalyseMapper;
import com.ruoyi.water.service.IElementService;
import com.ruoyi.water.service.IHourDataService;
import com.ruoyi.water.service.IMeterAnalyseService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.ArrayList;

@Service
public class MeterAnalyseServiceImpl extends ServiceImpl<MeterAnalyseMapper, MeterAnalyse> implements IMeterAnalyseService {

    @Autowired
    private IElementService elementService;

    @Autowired
    private IHourDataService hourDataService;

    @Autowired
    private MeterAnalyseMapper meterAnalyseMapper;  // 注入Mapper

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int calculateAndSaveDailyData(Date startDate, Date endDate) {
        // 1. 将结束日期向后延长一天，用于查询
        Date extendedEndDate = addOneDay(endDate);

        // 2. 获取所有元素
        List<Element> elements = elementService.list();
        int processedCount = 0;

        // 创建列表用于批量插入
        List<MeterAnalyse> meterAnalyseList = new ArrayList<>();

        // 3. 遍历每个元素
        for (Element element : elements) {
            Integer elementId = element.getId();
            String elementName = element.getElemName();

            // 4. 查询该元素在扩展日期范围内的所有小时数据
            List<HourData> hourDataList = getHourDataByElementAndDateRange(elementId, startDate, extendedEndDate);

            if (hourDataList.isEmpty()) {
                continue;
            }

            // 5. 按日期分组处理数据
            Map<LocalDate, List<HourData>> dailyDataMap = groupHourDataByDate(hourDataList);

            // 6. 处理每组数据并保存，但只保留原日期范围内的结果
            LocalDate originalStartDate = convertToLocalDate(startDate);
            LocalDate originalEndDate = convertToLocalDate(endDate);

            for (Map.Entry<LocalDate, List<HourData>> entry : dailyDataMap.entrySet()) {
                LocalDate currentDate = entry.getKey();

                // 只处理原日期范围内的日期
                if (currentDate.isBefore(originalStartDate) || currentDate.isAfter(originalEndDate)) {
                    continue;
                }

                List<HourData> dailyData = entry.getValue();

                // 计算每日总流量
                double todayUsage = calculateTodayUsage(dailyData);

                // 计算每日最小流量及时间
                HourData minFlowData = findMinFlowData(dailyData);

                // 构建分析结果并添加到列表
                MeterAnalyse meterAnalyse = buildMeterAnalyse(elementId, elementName, currentDate, todayUsage, minFlowData);
                meterAnalyseList.add(meterAnalyse);
                processedCount++;
            }
        }

        // 批量插入，忽略重复记录
        if (!meterAnalyseList.isEmpty()) {
            meterAnalyseMapper.insertBatchIgnoreDuplicates(meterAnalyseList);
        }

        return processedCount;
    }

    /**
     * 构建水表分析数据对象
     */
    private MeterAnalyse buildMeterAnalyse(Integer meterId, String meterName, LocalDate analyseDate,
                                           double todayUsage, HourData minFlowData) {
        MeterAnalyse meterAnalyse = new MeterAnalyse();

        // 设置基本信息
        meterAnalyse.setMeterId(meterId);
        meterAnalyse.setMeterName(meterName);
        meterAnalyse.setAnalyseDate(convertToDate(analyseDate));
        meterAnalyse.setTodayUsage(todayUsage);
        meterAnalyse.setRecordTime(new Date());

        // 设置最小流量信息
        if (minFlowData != null) {
            meterAnalyse.setTodayMinVal((double) minFlowData.getValue());
            meterAnalyse.setTodayMinvalTime(minFlowData.getValueTime());
        }

        return meterAnalyse;
    }

    /**
     * 将日期加一天
     */
    private Date addOneDay(Date date) {
        if (date == null) {
            return null;
        }
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.DATE, 1);
        return calendar.getTime();
    }

    /**
     * 根据元素ID和日期范围查询小时数据
     */
    private List<HourData> getHourDataByElementAndDateRange(Integer elementId, Date startDate, Date endDate) {
        QueryWrapper<HourData> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("meterId", elementId)
                .ge("valueTime", startDate)
                .le("valueTime", endDate);
        return hourDataService.list(queryWrapper);
    }

    /**
     * 将小时数据按日期分组
     */
    private Map<LocalDate, List<HourData>> groupHourDataByDate(List<HourData> hourDataList) {
        return hourDataList.stream()
                .collect(Collectors.groupingBy(
                        data -> convertToLocalDate(data.getValueTime())
                ));
    }

    /**
     * 计算当日总流量（0点到24点）
     */
    private double calculateTodayUsage(List<HourData> dailyData) {
        return dailyData.stream()
                .filter(data -> isWithinSameDay(data.getValueTime()))
                .mapToLong(HourData::getValue)
                .sum();
    }

    /**
     * 查找当日最小流量数据
     */
    private HourData findMinFlowData(List<HourData> dailyData) {
        return dailyData.stream()
                .filter(data -> isWithinSameDay(data.getValueTime()))
                .min((d1, d2) -> Long.compare(d1.getValue(), d2.getValue()))
                .orElse(null);
    }

    /**
     * 保存或更新水表分析数据
     */
    private void saveOrUpdateMeterAnalyse(Integer meterId, String meterName, LocalDate analyseDate,
                                          double todayUsage, HourData minFlowData) {
        // 检查是否已存在该日期的分析数据
        QueryWrapper<MeterAnalyse> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("meterId", meterId)
                .eq("analyseDate", convertToDate(analyseDate));

        MeterAnalyse meterAnalyse = getOne(queryWrapper);

        if (meterAnalyse == null) {
            meterAnalyse = new MeterAnalyse();
            meterAnalyse.setMeterId(meterId);
        }

        // 设置基本信息
        meterAnalyse.setMeterName(meterName);
        meterAnalyse.setAnalyseDate(convertToDate(analyseDate));
        meterAnalyse.setTodayUsage(todayUsage);
        meterAnalyse.setRecordTime(new Date());

        // 设置最小流量信息
        if (minFlowData != null) {
            meterAnalyse.setTodayMinVal((double) minFlowData.getValue());
            meterAnalyse.setTodayMinvalTime(minFlowData.getValueTime());
        }

        saveOrUpdate(meterAnalyse);
    }

    /**
     * 检查时间是否在当天（0点到24点）
     */
    private boolean isWithinSameDay(Date date) {
        if (date == null) {
            return false;
        }

        LocalDate dateToCheck = convertToLocalDate(date);
        LocalDateTime dateTime = convertToLocalDateTime(date);

        LocalDateTime startOfDay = dateToCheck.atStartOfDay();
        LocalDateTime endOfDay = dateToCheck.plusDays(1).atStartOfDay();

        return dateTime.isAfter(startOfDay) && dateTime.isBefore(endOfDay);
    }

    /**
     * Date 转换为 LocalDate
     */
    private LocalDate convertToLocalDate(Date date) {
        if (date == null) {
            return null;
        }
        return date.toInstant()
                .atZone(ZoneId.systemDefault())
                .toLocalDate();
    }

    /**
     * Date 转换为 LocalDateTime
     */
    private LocalDateTime convertToLocalDateTime(Date date) {
        if (date == null) {
            return null;
        }
        return date.toInstant()
                .atZone(ZoneId.systemDefault())
                .toLocalDateTime();
    }

    /**
     * LocalDate 转换为 Date
     */
    private Date convertToDate(LocalDate localDate) {
        if (localDate == null) {
            return null;
        }
        return Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
    }

    //以下为analyzeAndUpdateMeterData实现方法以及一些对应的函数
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int analyzeAndUpdateMeterData(Date startDate, Date endDate) {
        // 1. 查询指定日期范围内的所有计量分析数据
        QueryWrapper<MeterAnalyse> queryWrapper = new QueryWrapper<>();
        queryWrapper.ge("analyseDate", startDate)
                .le("analyseDate", endDate);
        List<MeterAnalyse> meterAnalyseList = list(queryWrapper);

        if (meterAnalyseList.isEmpty()) {
            return 0;
        }

        // 2. 按meterId分组处理
        Map<Integer, List<MeterAnalyse>> groupByMeterId = meterAnalyseList.stream()
                .collect(Collectors.groupingBy(MeterAnalyse::getMeterId));

        int processedCount = 0;

        // 3. 获取所有相关的元素信息，避免重复查询
        List<Integer> meterIds = new ArrayList<>(groupByMeterId.keySet());
        QueryWrapper<Element> elementQuery = new QueryWrapper<>();
        elementQuery.in("id", meterIds);
        Map<Integer, Element> elementMap = elementService.list(elementQuery).stream()
                .collect(Collectors.toMap(Element::getId, e -> e));

        // 4. 处理每个水表的数据
        for (Map.Entry<Integer, List<MeterAnalyse>> entry : groupByMeterId.entrySet()) {
            Integer meterId = entry.getKey();
            List<MeterAnalyse> analyses = entry.getValue();
            Element element = elementMap.get(meterId);

            // 如果元素不存在，跳过该组处理
            if (element == null) {
                continue;
            }

            // 处理该水表的每条分析记录
            for (MeterAnalyse analyse : analyses) {
                // 计算与基准值的偏差（最小流量）
                calculateMinValRelated(analyse, element);

                // 计算与基准值的偏差（用水量）
                calculateUsageRelated(analyse, element);

                // 计算上月同日数据（允许历史数据为0）
                calculateMonthAgoData(analyse, meterId);

                // 计算上年同日数据（允许历史数据为0）
                calculateYearAgoData(analyse, meterId);

                // 保存更新
                updateById(analyse);
                processedCount++;
            }
        }

        return processedCount;
    }

    /**
     * 计算最小流量相关的基准偏差值（基准值为Element表数据，非零判断保留）
     */
    private void calculateMinValRelated(MeterAnalyse analyse, Element element) {
        Double minVal = element.getMinVal();
        Double todayMinVal = analyse.getTodayMinVal();

        if (minVal == null || todayMinVal == null) {
            return;
        }

        // 基准值非零才计算百分比（避免无效值），偏差值始终计算
        analyse.setTodayMinvalBias(todayMinVal - minVal);
        if (minVal != 0) {
            analyse.setTodayMinvalPercent((todayMinVal - minVal) / minVal * 100);
        } else {
            analyse.setTodayMinvalPercent(null); // 基准值为0时百分比无意义
        }
    }

    /**
     * 计算用水量相关的基准偏差值（基准值为Element表数据，非零判断保留）
     */
    private void calculateUsageRelated(MeterAnalyse analyse, Element element) {
        Double dayUsage = element.getDayUsage();
        Double todayUsage = analyse.getTodayUsage();

        if (dayUsage == null || todayUsage == null) {
            return;
        }

        // 基准值非零才计算百分比，偏差值始终计算
        analyse.setTodayUsageBias(todayUsage - dayUsage);
        if (dayUsage != 0) {
            analyse.setTodayUsagePercent((todayUsage - dayUsage) / dayUsage * 100);
        } else {
            analyse.setTodayUsagePercent(null); // 基准值为0时百分比无意义
        }
    }

    /**
     * 计算上月同日的数据（移除历史数据≠0的判断，添加除以零安全处理）
     */
    private void calculateMonthAgoData(MeterAnalyse analyse, Integer meterId) {
        Date analyseDate = analyse.getAnalyseDate();
        if (analyseDate == null) {
            return;
        }

        // 计算上月同日日期
        LocalDate currentDate = convertToLocalDate(analyseDate);
        LocalDate monthAgoDate = currentDate.minusMonths(1);

        // 查询上月同日数据
        QueryWrapper<MeterAnalyse> query = new QueryWrapper<>();
        query.eq("meterId", meterId)
                .eq("analyseDate", convertToDate(monthAgoDate));

        MeterAnalyse monthAgoData = getOne(query);
        if (monthAgoData == null) {
            return; // 历史数据不存在时才跳过
        }

        // 处理最小流量相关（允许monthAgoMinVal为0，仅判断非空）
        Double currentMinVal = analyse.getTodayMinVal();
        Double monthAgoMinVal = monthAgoData.getTodayMinVal();
        if (currentMinVal != null && monthAgoMinVal != null) {
            analyse.setMonthagoMinval(monthAgoMinVal);
            analyse.setMonthagoMinvalBias(currentMinVal - monthAgoMinVal);
            // 历史数据为0时，百分比设为null（避免除以零），偏差值正常保留
            analyse.setMonthagoMinvalPercent(monthAgoMinVal != 0 ?
                    (currentMinVal - monthAgoMinVal) / monthAgoMinVal * 100 : null);
        }

        // 处理用水量相关（允许monthAgoUsage为0，仅判断非空）
        Double currentUsage = analyse.getTodayUsage();
        Double monthAgoUsage = monthAgoData.getTodayUsage();
        if (currentUsage != null && monthAgoUsage != null) {
            analyse.setMonthagoUsage(monthAgoUsage);
            analyse.setMonthagoUsageBias(currentUsage - monthAgoUsage);
            // 历史数据为0时，百分比设为null
            analyse.setMonthagoUsagePercent(monthAgoUsage != 0 ?
                    (currentUsage - monthAgoUsage) / monthAgoUsage * 100 : null);
        }
    }

    /**
     * 计算上年同日的数据（移除历史数据≠0的判断，添加除以零安全处理）
     */
    private void calculateYearAgoData(MeterAnalyse analyse, Integer meterId) {
        Date analyseDate = analyse.getAnalyseDate();
        if (analyseDate == null) {
            return;
        }

        // 计算上年同日日期
        LocalDate currentDate = convertToLocalDate(analyseDate);
        LocalDate yearAgoDate = currentDate.minusYears(1);

        // 查询上年同日数据
        QueryWrapper<MeterAnalyse> query = new QueryWrapper<>();
        query.eq("meterId", meterId)
                .eq("analyseDate", convertToDate(yearAgoDate));

        MeterAnalyse yearAgoData = getOne(query);
        if (yearAgoData == null) {
            return; // 历史数据不存在时才跳过
        }

        // 处理最小流量相关（允许yearAgoMinVal为0，仅判断非空）
        Double currentMinVal = analyse.getTodayMinVal();
        Double yearAgoMinVal = yearAgoData.getTodayMinVal();
        if (currentMinVal != null && yearAgoMinVal != null) {
            analyse.setYearagoMinval(yearAgoMinVal);
            analyse.setYearagoMinvalBias(currentMinVal - yearAgoMinVal);
            // 历史数据为0时，百分比设为null
            analyse.setYearagoMinvalPercent(yearAgoMinVal != 0 ?
                    (currentMinVal - yearAgoMinVal) / yearAgoMinVal * 100 : null);
        }

        // 处理用水量相关（允许yearAgoUsage为0，仅判断非空）
        Double currentUsage = analyse.getTodayUsage();
        Double yearAgoUsage = yearAgoData.getTodayUsage();
        if (currentUsage != null && yearAgoUsage != null) {
            analyse.setYearagoUsage(yearAgoUsage);
            analyse.setYearagoUsageBias(currentUsage - yearAgoUsage);
            // 历史数据为0时，百分比设为null
            analyse.setYearagoUsagePercent(yearAgoUsage != 0 ?
                    (currentUsage - yearAgoUsage) / yearAgoUsage * 100 : null);
        }
    }
}